/**
 * @author Giuseppe Mendola
 * @author Nicolas Latorre
 * @author Virginie Blancs
 */

package sa4

import javax.servlet.http._
import scala.xml._
import javax.imageio.ImageIO
import javax.servlet.ServletConfig
import sa4.persistence._
import org.squeryl.KeyedEntity
import org.squeryl.SessionFactory
import org.squeryl.Session
import org.squeryl.adapters.H2Adapter
import scala.util.matching.Regex
import org.squeryl.adapters.H2Adapter
import java.sql.Timestamp
import java.sql.Date
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.dsl.ast.LogicalBoolean
import org.squeryl.annotations.OptionType
import java.io._

class Bet extends Framework {
  override def init(config: ServletConfig) = {
    super.init(config)
    initRoutes

    transaction {
      UsiBets.drop
    }
    transaction {
      UsiBets.create
    }
    transaction {
      persistence.newUser("ParamsAirline", "Nicolas", "Latorre", "params@air.com", "1234", new java.util.Date("01/26/1988"))
      val virgie = persistence.newUser("ProfInBikini", "Virginie", "Blancs", "lol@trolol.com", "5678", new java.util.Date("11/04/1991"))
      val peppe = persistence.newUser("Salam", "Giuseppe", "Mendola", "salam@hoban.com", "suca", new java.util.Date("01/26/1988"))

    		  persistence.newBet("Bet1", peppe,"Descrizione1", new java.util.Date())
    	      persistence.newBet("Bet2", peppe,"Descrizione2", new java.util.Date())
      
            persistence.addBet(persistence.getUser("ParamsAirline"), persistence.getBet("Bet1"))
            persistence.addBet(persistence.getUser("ParamsAirline"), persistence.getBet("Bet2"))
      val choice1 = UsiBets.betchoices.insert(new BetChoice("A", 2, "Bet1"))
      UsiBets.betchoices.insert(new BetChoice("B", 3, "Bet1"))
      UsiBets.currentBets.insert(new CurrentBet("ProfInBikini", persistence.getBet("Bet1").id, 20, 40, new BetChoice("A", 2, "Bet1")))
    } 

  }

  override def service(req: HttpServletRequest, resp: HttpServletResponse) {
    super.service(req, resp)
    //Session setup
    var currentContext = session.getCurrentContext
    currentContext = session.newContext(req, resp, currentContext)
    var cc = currentContext().session
    cc.setMaxInactiveInterval(60)
  }

  def initRoutes(): Unit = {
    ///////////////////////////////
    // TODO: Add your routes code here
    ///////////////////////////////
    routing.addRoute("/login", login)
    routing.addRoute("/logout", logout)
    routing.addRoute("/home", home)
    routing.addRoute("/register", register)
    routing.addRoute("/setResp", setResp)
    routing.addRoute("/addBet", addBetForm)
    routing.addRoute("/bet", displayBet)
    routing.addRoute("/mybet",displayMyBet)
    routing.addRoute("/showCurrentBets", showCurrentBets)
    routing.addRoute("/showbets", showbets)
    routing.addRoute("/placeBet", placeBet)
    routing.addRoute("/img/glyphicons-halflings-white.png", iconsw)
    routing.addRoute("/img/glyphicons-halflings.png", icons)
    routing.addRoute("/showAddedBets",myAdded)
    routing.addRoute("/updateDB", updateDB)
    initDefaultRoutes()
  }

  def initDefaultRoutes(): Unit = {
    routing.addRoute("/", startPage)
    
    ////////////////////////////////////
  }

  ///////////////////////////////
  // TODO: Add your functions here
  ///////////////////////////////

  /**
   * Function that load the start page of the application.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def startPage(req: HttpServletRequest, resp: HttpServletResponse) {
    var user = getUserInfo(req, resp)
    print(user)
    if (user == "") {
      session.updateSession
      val xml = template.loadPage("src/main/scala/sa4/betapp/index.html")
      val html = form.prepareForm(xml, routing)
      resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
      resp.setContentType("text/html")
    } else {
      print("home")
      resp.sendRedirect(resp.encodeRedirectURL("/home"))
    }
  }

  /**
   * Function that load the home page of the application.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def home(req: HttpServletRequest, resp: HttpServletResponse) {
    session.updateSession
    val cookie=getUserInfo(req, resp)
    if (cookie==""){
      resp.sendRedirect(resp.encodeRedirectURL("/login"))
    }
    else{
    val xml = template.loadPage("src/main/scala/sa4/betapp/home.html")
    val id=session.getIdSession
    val name = persistence.getUser(cookie)
    val new_xml = template.processTemplate(userPage(name))
    val html = form.prepareForm(new_xml, routing)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
    resp.setContentType("text/html")
    }
  }
  

  /**
   * Function that load the template for the registration in the application.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def register(req: HttpServletRequest, resp: HttpServletResponse) {
    session.updateSession
    val xml = template.setUpTemplate("src/main/scala/sa4/betapp/register.xml")
    val html = form.prepareForm(xml, routing)
    resp.setStatus(HttpServletResponse.SC_OK)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
    if (!req.isRequestedSessionIdValid) {
      var dest = resp.encodeRedirectURL("/")
      resp.sendRedirect(dest)
    }
  }

  /**
   * Function that set the response.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def setResp(req: HttpServletRequest, resp: HttpServletResponse) {
    resp.setStatus(200)
    resp.setContentLength(0)
    resp.setContentType("application/xml")
  }
  
  /**
   * Function that load the template for add a new bet.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def addBetForm(req: HttpServletRequest, resp: HttpServletResponse) {
    val user = persistence.getUser(getUserInfo(req, resp))
    if (user.level < 7) {
      val xml = template.processTemplate(lowlevel)
      val html = form.prepareForm(xml, routing)
      resp.setContentType("text/html")
      resp.setStatus(HttpServletResponse.SC_OK)
      resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
    } else {
      val xml = template.setUpTemplate("src/main/scala/sa4/betapp/addBet.xml")
      val html = form.prepareForm(xml, routing)
      resp.setContentType("text/html")
      resp.setStatus(HttpServletResponse.SC_OK)
      resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
    }
  }

  /**
   * Function that load the template for the login in the applicaiton.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def login(req: HttpServletRequest, resp: HttpServletResponse) {
    val xml = template.setUpTemplate("src/main/scala/sa4/betapp/login.xml")
    val html = form.prepareForm(xml, routing)
    resp.setContentType("text/html")
    resp.setStatus(HttpServletResponse.SC_OK)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }

  /**
   * Function that perform a logout from the application.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def logout(req: HttpServletRequest, resp: HttpServletResponse) {
    print("logout")
    var cookies=req.getCookies()
    for (i<-cookies){
      i.setValue("")
      i.setMaxAge(0)
      resp.addCookie(i)
    }
    var dest = resp.encodeRedirectURL("/")
      resp.sendRedirect(dest)
    
  }

  /**
   * Function that call the login function to see if the login is correct, and if it is the case it will redirect the user to the home, otherwise we have to retry the login.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def loginHandler(req: HttpServletRequest, resp: HttpServletResponse) = {
    val user = req.getParameter("username")
    val pass = req.getParameter("password")
    val loginResult = persistence.loginMethod(user, pass)
    if (loginResult) {
      var c = new Cookie("userName",user)
      c.setPath("/")
      resp.addCookie(c)
      var dest = resp.encodeRedirectURL("/home")
      resp.sendRedirect(dest)
    } else {
      var dest = resp.encodeRedirectURL("/")
      resp.sendRedirect(dest)
    }
  }

  /**
   * Function that load the added function of a user in the application.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def myAdded(req: HttpServletRequest, resp: HttpServletResponse)={
    resp.setContentType("text/html")
    resp.setStatus(HttpServletResponse.SC_OK)
    val cookie = getUserInfo(req, resp)
    val user = persistence.getUser(cookie)
    val xml = persistence.listOfAddedBets(user)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(xml))
  }

  def updateDB(req: HttpServletRequest, resp: HttpServletResponse) = {
	    val currentDate = new java.util.Date()
	    transaction {
	      val elems = UsiBets.bets
	      for (e <- elems) {
	        if (currentDate.getDate() == e.endDate.getDate() && currentDate.getMonth() == e.endDate.getMonth() && currentDate.getYear() == e.endDate.getYear()) {
	          persistence.addWin(e)
	        }
	      }
	    }
	    resp.sendRedirect("/home")
	    //    var text = <p>Removed Bets</p>
	    //    resp.setContentType("text/html")
	    //    resp.setStatus(HttpServletResponse.SC_OK)
	    //    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(text))

	  }
  
  /**
   * Function that add a user in the database.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def addUser(req: HttpServletRequest, resp: HttpServletResponse) = {
    val userName = req.getParameter("username")
    val name = req.getParameter("name")
    val surname = req.getParameter("surname")
    val email = req.getParameter("email")
    val password = req.getParameter("password")
    transaction {

      if (persistence.mailUnique(email) && persistence.userUnique(userName)) {
        persistence.newUser(userName, name, surname, email, password, new java.util.Date())
        resp.sendRedirect("/")
      } else {
        resp.sendRedirect("/register")

      }

    }
  }

  /**
   * Function that add a bet in the database.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def addBetHandler(req: HttpServletRequest, resp: HttpServletResponse) = {
    val cookie = getUserInfo(req, resp)
    val user = persistence.getUser(cookie)
    var counter = 0
    var choice = ""
    var rate = ""
    var route = ""
    var id = 0L
    val title = req.getParameter("betTitle")
    val description = req.getParameter("description")
    val endDate = req.getParameter("endDate")
    if (title == "" || description == "" || endDate == "") {
      resp.sendRedirect("/addBet")
    }
    var endDateForm = endDate.split("/")
    var date = endDateForm(0).toInt
    var month = endDateForm(1).toInt - 1
    var year = endDateForm(2).toInt - 1900
    for (i <- 1 until 6) {
      choice = req.getParameter("choice" + i)
      rate = req.getParameter("rate" + i)
      if (choice != "" && rate != "") {
        counter += 1
      }
    }
    if (counter >= 2) {
      if (persistence.betUnique(title)) {
        for (i <- 1 until 6) {
          choice = req.getParameter("choice" + i)
          rate = req.getParameter("rate" + i)
          if (choice != "" && rate != "") {
            transaction {
              UsiBets.betchoices.insert(new BetChoice(choice, rate.toDouble, title))
            }
          }
        }
        transaction {
          persistence.newBet(title, user, description, new java.util.Date(year, month, date))
          id = persistence.getBet(title).id
        } 
        resp.sendRedirect("/home")
      }
      else{
        resp.sendRedirect("/addBet")
      }
    } else {
      resp.sendRedirect("/addBet")
    }
  }

  /**
   * Function that displays the form to place a bet if the user has never betted on it, redirects to the home page otherwise
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def displayBet(req: HttpServletRequest, resp: HttpServletResponse) = {
    var betid = req.getParameter("id").toLong
    val userName = getUserInfo(req, resp)
    var added = persistence.isBetted(userName, betid)
    var creater = persistence.isCreater(userName, betid)
    if (!added && !creater) {
      val xml = template.processTemplate(persistence.betInfo(betid))
      val html = form.prepareForm(xml, routing)
      resp.setContentType("text/html")
      resp.setStatus(HttpServletResponse.SC_OK)
      resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
    } else {
      resp.sendRedirect("/home")
    }
  }
  
  /**
   * Function that displays the bet that the user added.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def displayMyBet(req: HttpServletRequest, resp: HttpServletResponse)={
    var betid = req.getParameter("id").toLong
    val xml = template.processTemplate(persistence.placeWinner(betid))
    val html = form.prepareForm(xml, routing)
    resp.setContentType("text/html")
    resp.setStatus(HttpServletResponse.SC_OK)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html)) 
  }

  /**
   * Function that retrive the informations from the form and place a bet.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def placeBet(req: HttpServletRequest, resp: HttpServletResponse) = {
    val betAmount = req.getParameter("yourBet")
    val choiceId = req.getParameter("choice").toLong
    val choice = persistence.getChoice(choiceId)
    val userName = getUserInfo(req, resp)
    val user = persistence.getUser(userName)
    var betId = persistence.getBet(choice.betName).id
    if (betAmount == "" || betAmount.toInt > user.credits || betAmount.toInt == 0) {
      val url = "/bet?id=" + betId
      resp.sendRedirect(url)
    } else {
      val possibleGain = betAmount.toInt * choice.rate
      val newCredits = user.credits - betAmount.toInt
      transaction {
        UsiBets.currentBets.insert(new CurrentBet(userName, betId, betAmount.toInt, possibleGain, choice))
        persistence.updateCredits(user, newCredits)
      }
      resp.sendRedirect("/home")
    }

  }
  
  /**
   * Function that determines who win a bet.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def setWinner(req: HttpServletRequest, resp: HttpServletResponse)={
    val choiceId =req.getParameter("choice").toLong
    val bet=persistence.getBet(req.getParameter("betName"))
    val choice = persistence.getChoice(choiceId)
    persistence.setWinner(bet,choice)
    persistence.addWin(bet)
    resp.sendRedirect("/home")
  }

  /**
   * Function that generate a template for the user page usign scala code.
   * @param user		a sa4.persistence.User object that represent a user.
   * @return			a scala.xml.Elem that contains the template with the user informations.
   */
  def userPage(user: User) = {
    <surround with="src/main/scala/sa4/betapp/home.html" at="body">
      <div class="offset5"><h1>{ user.userName }</h1>
      <button id="refresh" class="btn btn-info">Refresh</button></div>
      <div class="container-fluid">
        <div class="row-fluid">
          <div class="span1">
          </div>
          <div class="span2 ">
            { user.name }<br/>
            Credits:<br/>
            Level:
          </div>
          <div class="span2">
            { user.surname }<br/>
            { user.credits }<br/>
            { user.level }
          </div>
        </div>
      </div>
    </surround>

  }
  
  /**
   * Function that create a template for a low level experience that doesn't allow you to place a bet.
   * @return 	a scala.xml.Elem that contains the template.
   */
  def lowlevel={
    <surround with="src/main/scala/sa4/betapp/home.html" at="body">
      <h1>YOUR LEVEL IS TO LOW TO ADD A BET</h1><h2>(at least level 7)</h2>
    </surround>
  }

  /**
   * Function that display the current bets of the user in the page.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def showCurrentBets(req: HttpServletRequest, resp: HttpServletResponse) = {
    resp.setContentType("text/html")
    resp.setStatus(HttpServletResponse.SC_OK)
    val cookie = getUserInfo(req, resp)
    val user = persistence.getUser(cookie)
    val xml = persistence.listCurrentBets(user)
      
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(xml))
  }
  
  /**
   * Function that display all the bets in the page.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def showbets(req: HttpServletRequest, resp: HttpServletResponse) = {
    resp.setContentType("text/html")
    resp.setStatus(HttpServletResponse.SC_OK)
    val xml = persistence.listBets
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(xml))
  }
  
  /**
   * Function that retrive the user informations from the cookie.
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def getUserInfo(req: HttpServletRequest, resp: HttpServletResponse) = {
    var value=""
    val cookies = req.getCookies()
    for (cookie<- cookies){
      if (cookie.getName=="userName"){
        value=cookie.getValue()
      }
    }
    val username = value
    username
  }

  /**
   * Function that load an image
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def iconsw(req: HttpServletRequest, resp: HttpServletResponse) = {
    val img = template.loadImage("src/main/scala/sa4/bootstrap/img/glyphicons-halflings-white.png")
    val fileType = getServletContext().getMimeType("glyphicons-halflings-white.png")
    val out = resp.getOutputStream();
    resp.setContentType(fileType)
    ImageIO.write(img, "png", out);
  }

  /**
   * Function that load an image
   * @param req 	an HttpServletRequest to the servlet.
   * @param resp 	an HttpSErvletResponse from the servlet.
   */
  def icons(req: HttpServletRequest, resp: HttpServletResponse) = {
    val img = template.loadImage("src/main/scala/sa4/bootstrap/img/glyphicons-halflings.png")
    val fileType = getServletContext().getMimeType("glyphicons-halflings.png")
    val out = resp.getOutputStream();
    resp.setContentType(fileType)
    ImageIO.write(img, "png", out);
  }
  
  
}